#pragma once
#include <vector>
#include <utility>
#include "Mutex.hpp"
#include "Sem.hpp"

using namespace MutexModule;
using namespace SemModule;

static int defaultcap = 5;

template <class T>
class RingQueue
{
public:
    RingQueue(int cap=defaultcap)
        : _rq(cap,0),_cap(cap), _blank(cap), _data(0), _c(0), _p(0)
    {
        
    }

    template <class T1>
    void Equeue(T1 &&data)
    {
        // 1.申请空白信号量
        _blank.P();
        {
            // 2.申请锁，生产者直接互斥
            MutexGuard mg(_pmutex);
            // 3.生产
            _rq[_p] = std::forward<T1>(data);
            // 4.更新指针，并环绕
            ++_p %= _cap;
        }
        // 5.释放数据信号量
        _data.V();
    }

    template <class T1>
    void Pop(T1 *ret)
    {
        _data.P();
        {
            MutexGuard mg(_cmutex);
            *ret = std::forward<T1>(_rq[_c]);
            ++_c %= _cap;
        }
        _blank.V();
    }

    ~RingQueue()
    {
    }

private:
    std::vector<T> _rq;
    int _cap;
    Sem _blank;
    Sem _data;
    int _c;
    int _p;
    Mutex _pmutex;
    Mutex _cmutex;
};